import * as fs from "fs";
import * as path from "path";
import request = require("request");
import * as child_process from "child_process";

import log from "../lib/log";
import { info } from "../lib/info";
import { Config, Result } from "../typing";
import { compile, keyFormat } from "../lib/compile";
import { Service } from "../lib/service";

export default class Nginx extends Service {

    public async start() {

        const { root, bin, nginxConfig } = this.config.service.nginx;

        // 启动nginx
        const argList = ["-p", root, "-c", nginxConfig];
        log.app.info(`启动nginx: ${ bin } ${ argList.join(" ") }`);
        return super.start(bin, argList);
    }

    public run(cmd: string, argList: string[]): child_process.ChildProcessWithoutNullStreams {
        const worker = child_process.spawn(cmd, argList);
        worker.stdout.on("data", (data: string) => {
            if (this.filter(data)) {
                log[this.serviceName].info(data.toString());
            }
        });
        worker.stderr.on("data", (data: string) => {
            log[this.serviceName].error(data.toString());
        });
        return worker;
    }

    public configService() {
        const nginxDir = this.config.service.nginx.root;

        // 载入nginx模板文件
        const template = fs.readFileSync(this.config.service.nginx.template).toString();
    
        // 编译模板写入nginx配置
        fs.writeFileSync(path.resolve(nginxDir, "conf/lyx.conf"), compile(template, keyFormat(this.config.service)));
    }

    public async healthChecks(): Promise<boolean> {
        return new Promise((resolve) => {
            log.request.info("http://localhost:8800");
            request.get("http://localhost:8800", (err, res) => {
                resolve(!err && res.statusCode == 200 && res.body);
            });
        });
    }

    /**
     * 更新模板文件
     * @param content 
     * @param config 
     */
    public static async updateTemplate(content: string, config: Config): Promise<Result> {
        const result: Result = { success: false };
        try {
            // 更新模板文件
            await fs.promises.writeFile(config.service.nginx.template, content);

            // 编译模板写入nginx配置
            const nginxDir = config.service.nginx.root;
            await fs.promises.writeFile(path.resolve(nginxDir, "conf/lyx.conf"), compile(content, keyFormat(config.service)));
            result.success = true;
        } catch (error) {
            log.app.error(error);
            result.message = error.message.toString();
        }
        return result;
    }

    /**
     * 重新载入nginx配置
     */
    public static reloadConfig(config: Config): Result {
        const result: Result = { success: false };
        try {
            const { bin, nginxConfig, root } = config.service.nginx;
            let reloadResult: any;
            if (info.system === "windows") {
                reloadResult = child_process.spawnSync("nginx.exe", ["-s", "reload"], { cwd: root });
            } else {
                reloadResult = child_process.spawnSync(bin, ["-s", "reload", "-c", nginxConfig, "-p", root]);
            }
            result.success = true;
            result.message = reloadResult.output[2].toString();
        } catch (error) {
            log.app.error(error);
            result.message = error.message.toString();
        }
        return result;
    }

    /**
     * 检查nginx配置
     */
    public static checkConfig(config: Config): Result {
        const result: Result = { success: false };
        try {
            const { bin, root, nginxConfig } = config.service.nginx;
            let checkResult: any;
            if (info.system === "windows") {
                checkResult = child_process.spawnSync("nginx.exe", ["-t"], { cwd: root });
            } else {
                checkResult = child_process.spawnSync(bin, ["-t", "-c", nginxConfig]);
            }
            result.success = true;
            result.message = checkResult.output[2].toString();
        } catch (error) {
            log.app.error(error);
            result.message = error.message.toString();
        }
        return result;
    }

    /**
     * 更新配置文件
     * @param configStr 新配置
     * @param config 配置文件
     */
    public static async updateConfig(config: Config, configStr: string): Promise<boolean> {
        try {
            // 更新模板文件
            await fs.promises.writeFile(config.service.nginx.template, configStr);

            // 编译模板写入nginx配置
            const nginxDir = config.service.nginx.root;
            await fs.promises.writeFile(path.resolve(nginxDir, "conf/lyx.conf"), compile(configStr, keyFormat(config.service)));
            return true;
        } catch (error) {
            log.app.error(error);
            return false;
        }
    }

    /**
     * 获取配置文件
     * @param config 配置文件
     */
    public static getConfig(config: Config): Promise<string> {
        const template = config.service["nginx"].template;
        return new Promise((resolve) => {
            fs.readFile(template, (error, data) => {
                if (error) {
                    log["nginx"].info("getConfig", error);
                    resolve("");
                } else {
                    resolve(data.toString());
                }
            });
        });
    }

    /**
     * 监听配置文件变动
     * @param config 配置文件
     */
    public static monitorConfig(config: Config, callback) {
        fs.watchFile(config.service["nginx"].template, { interval: 500 }, callback);
    }
}